//
// Ephi - simulation of magnetic fields and particles
// Copyright (C) 2007, 2008 Indrek Mandre <indrek(at)mare.ee>
// For more information please see http://www.mare.ee/indrek/ephi/
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License along
// with this program; if not, write to the Free Software Foundation, Inc.,
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
//

#ifndef __coil_hpp__
#define __coil_hpp__

/** Abstract class for coil generation. */
class CoilFactory
{
public:
  virtual ~CoilFactory () { }

  /** Make a coil. */
  virtual bool make (Statics& statics, const vect3d& pos, const vect3d& normal,
      prec_t radius, prec_t wr, prec_t I, prec_t q_per_m) const = 0;

  /** Make an opposing coilpair with specified distance apart. */
  virtual bool make_coilpair (Statics& statics, const vect3d& pos, const vect3d& normal,
      prec_t distance, prec_t radius, prec_t wr, prec_t I, prec_t q_per_m) const
  {
    vect3d n = normal.normal();
    return make (statics, pos + 0.5 * distance * n, -normal, radius, wr, I, q_per_m) &&
        make (statics, pos - 0.5 * distance * n, normal, radius, wr, I, q_per_m);
  }
};

/** Generate coils using a specific shape matrix. */
class ShapedCoilFactory : public CoilFactory
{
public:
  ShapedCoilFactory (int n = 1);
  ShapedCoilFactory (int w, int h, prec_t hs = 1.0, prec_t vs = 1.0);
  virtual ~ShapedCoilFactory();

  struct coil_str
  {
    prec_t x;
    prec_t R;
    prec_t I;
    prec_t q;
  };
  typedef std::vector<coil_str> coils_t;

  bool make (Statics& statics, const vect3d& pos, const vect3d& normal,
      prec_t radius, prec_t wr, prec_t I, prec_t q_per_m) const;
  void add (coils_t& coils, prec_t pos, prec_t radius, prec_t wr,
      prec_t I, prec_t q_per_m) const;

  void set(int x, int y, bool v);
  void set_all (bool v);
  void set_circle ();

  int get_width () const { return width; }
  int get_height () const { return height; }
  prec_t get_hscale () const { return hscale; }
  prec_t get_vscale () const { return vscale; }
  void set_scale (prec_t hs, prec_t vs) { hscale = hs; vscale = vs; }

  bool get(int x, int y, vect3d& offset) const;
  int count() const;
  void print ();


private:
  int width, height;
  prec_t hscale, vscale;
  std::vector<bool> grid;
};

/** Calculate the b-field/1A of a coil with given radius at given axial and radial coordinates. */
extern void calcCoilBField (prec_t R, prec_t a, prec_t r,
  prec_t& Ba, prec_t& dBada, prec_t& dBadr, prec_t& d2Badadr,
  prec_t& Br, prec_t& dBrda, prec_t& dBrdr, prec_t& d2Brdadr);

/** Calculate the e-field/1C of a ring of charge with given radius at given axial and radial coordinates. */
extern void calcCoilEField (prec_t R, prec_t a, prec_t r,
    prec_t& Ea, prec_t& dEada, prec_t& dEadr, prec_t& d2Eadadr,
    prec_t& Er, prec_t& dErda, prec_t& dErdr, prec_t& d2Erdadr);

#endif // !__coil_hpp__

